<template>
  <div class="page__report_manage">
  <!-- <el-dialog :visible="show" @close="close" width="80%"> -->
    <div class="comp__report_manager">
      <top-header @change="handleHeaderAction"
        :page-mode="pageMode"
        :has-preview-nodes="previewNodes.length > 0"
        @appid-change="handleAppChange"
        @change-mode="changePageMode" />
      <!-- <list-tree class="list__body" v-show="pageMode === 'list'" :list="list" @change="setEditDialog" :nodes="nodes"
        ref="listTree" /> -->
      <data-list
        class="list__body"
        v-show="pageMode === 'list'"
        :list="list"
        @action="handleItemAction"
        :nodes="list"
      />
      <preview-list  v-show="pageMode === 'batch_import'"  :list="previewNodes" />
    </div>
    <el-dialog :title="editDialog.title" :visible.sync="editDialog.show" append-to-body width="30%" :close-on-click-modal="false">
      <el-form label-width="80px">
        <el-form-item label="事件ID">
          <el-input v-model="editDialog.button_id" :disabled="editDialog.type === 'edit'" />
        </el-form-item>
        <el-form-item label="事件名称">
          <el-input v-model="editDialog.button_name" />
        </el-form-item>
        <el-form-item label="父节点">
          <el-select filterable clearable
            :disabled="editDialog.type === 'add-sub'"
            v-model="editDialog.parent_id" placeholder="根节点">
            <el-option v-for="item in editNodes" :key="item.button_id" :label="item.button_name" :value="item.button_id" />
          </el-select>
        </el-form-item>
      </el-form>
      <div slot="footer">
        <el-button @click="editDialog.show = false">取消</el-button>
        <el-button type="primary" @click="handleConfirmChange">确定</el-button>
      </div>
    </el-dialog>
  </div>
  <!-- </el-dialog> -->
</template>

<script>
import { addButtonEventApi, updateButtonEventApi, deleteButtonEventApi, uploadBatchButtonEventApi, previewBatchButtonEventApi, confirmBatchButtonEventApi, getButtnEventListApi } from '@/api/report/button-events'
import TopHeader from './header.vue'
// import ListTree from './list-tree.vue'
import previewList from './preview-list.vue'
import { read, utils } from 'xlsx'
import { parseTime } from '@/utils/index'
import DataList from './list.vue'

export default {
  data: () => {
    return {
      pageMode: 'list', // list, batch_import
      previewNodes: [],
      list: [],
      nodes: [],
      editNodes: [],
      maxId: 0,
      editDialog: {
        show: false,
        title: '',
        type: '', // edit, add
        parent_id: null,
        button_id: '',
        button_name: ''
      },
      queryParams: {}
    }
  },
  components: {
    TopHeader,
    // ListTree,
    DataList,
    previewList
  },
  methods: {
    handleAppChange (appid) {
      this.queryParams.appid = appid
      this.initNodesData()
    },
    changePageMode (mode) {
      this.pageMode = mode
      if (mode === 'list') {
        this.previewNodes = []
      }
    },
    handleItemAction (val) {
      const { type, item } = val
      if (type === 'select') return this.handleItemSelect(item)
      const title = type === 'edit' ? '编辑事件' : '添加子节点'
      const button_name = type === 'add-sub' ? '' : item.button_name
      const params = { type, title, ...item, button_name }
      this.setEditDialog(params)
    },
    // eslint-disable-next-line sonarjs/cognitive-complexity
    handleItemSelect (val) {
      const status = val.checked
      const setNodeStatus = (nodes, id, status, recursion = true) => {
        const index = nodes.get(id).index
        const target = this.list[index]
        target.checked = status
        setParentNodeStatus(nodes, id)
        if (!target.childs.length || !recursion) return
        const len = target.childs.length
        for (let i = 0; i < len; i++) {
          const child_id = target.childs[i]
          setNodeStatus(nodes, child_id, status)
        }
      }
      const detechChildStatus = (nodes, id) => {
        const index = nodes.get(id).index
        const target = this.list[index]
        if (!target.childs.length) return 'checked'
        const len = target.childs.length
        let checked = 0
        let hasHalf = false
        for (let i = 0; i < len; i++) {
          const cid = target.childs[i]
          const cindex = nodes.get(cid).index
          const cstatus = this.list[cindex].checked
          // eslint-disable-next-line sonarjs/no-duplicate-string
          if (cstatus === 'half-checked') {
            hasHalf = true
            break
          }
          if (cstatus === 'checked') {
            checked++
          }
        }
        if (hasHalf) return 'half-checked'
        if (checked === len) return 'checked'
        if (checked === 0) return ''
        return 'half-checked'
      }
      const setParentNodeStatus = (nodes, id) => {
        const index = nodes.get(id).index
        const parentIds = this.list[index].parent_ids
        if (!parentIds.length) return
        const len = parentIds.length
        for (let i = len - 1; i >= 0; i--) {
          const pid = parentIds[i]
          const pstatus = detechChildStatus(nodes, pid)
          setNodeStatus(nodes, pid, pstatus, false)
        }
      }
      setNodeStatus(this.nodes, val.button_id, status === 'checked' ? '' : 'checked')
    },
    selectAll () {
      const isNotAllChecked = this.list.some((v) => v.checked === 'half-checked' || v.checked === '')
      if (isNotAllChecked) {
        this.list.forEach((v) => (v.checked = 'checked'))
      } else {
        this.list.forEach((v) => (v.checked = ''))
      }
    },
    revertAll () {
      this.list.forEach((v) => {
        if (v.checked === 'checked') v.checked = ''
        else if (v.checked === '') v.checked = 'checked'
      })
    },
    setEditDialog (params) {
      const { type, title, parent_id, button_id, button_name } = params || {}
      this.editDialog.title = title || ''
      this.editDialog.type = type || 'add'

      this.editDialog.button_name = button_name || ''
      this.editDialog.show = true
      if (type === 'edit') {
        this.editNodes = this.list.filter((v) => !v.parent_ids.includes(button_id))
        this.editDialog.button_id = button_id || ''
        this.editDialog.parent_id = parent_id || null
        return
      }
      if (type === 'add') {
        this.editNodes = this.list.concat()
        this.editDialog.button_id = this.maxId + 1
        this.editDialog.parent_id = null
        return
      }
      if (type === 'add-sub') {
        this.editNodes = [this.nodes.get(button_id)]
        this.editDialog.button_id = this.maxId + 1
        this.editDialog.parent_id = button_id
        return
      }
      if (type !== 'edit') {
        this.editDialog.button_id = button_id || this.maxId + 1
        this.editNodes = this.list.concat()
      } else {
        this.editNodes = this.list.filter((v) => !v.parent_ids.includes(button_id))
        this.editDialog.button_id = button_id || ''
      }
    },
    handleConfirmChange () {
      if (!this.detectParamsValid()) return

      const methods = {
        add: this.add,
        'add-sub': this.add,
        edit: this.edit,
        select: this.select,
        revert: this.revert
      }
      methods[this.editDialog.type] && methods[this.editDialog.type]()
    },
    detectParamsValid () {
      const { button_id, button_name, type, parent_id } = this.editDialog
      if (button_id === '' || button_name === '') {
        this.$message.error('添加失败！事件ID/名称不能为空')
        return false
      }
      if (!/^\d+$/.test(button_id)) {
        this.$message.error('添加失败！事件ID仅支持整数')
        return false
      }
      const exist = this.list.some(item => item.button_id === parseInt(button_id))
      if (exist && type !== 'edit') {
        this.$message.error('添加失败！事件ID已存在')
        return false
      }
      if (!button_name) {
        this.$message.error('请输入按钮名称')
        return false
      }
      if (button_id === parent_id) {
        this.$message.error('修改失败！不可设置子节点为父节点')
        return false
      }
      return true
    },
    async edit () {
      const params = {
        appid: this.queryParams.appid,
        button_id: this.editDialog.button_id,
        button_name: this.editDialog.button_name,
        parent_id: this.editDialog.parent_id
      }
      const data = await updateButtonEventApi(params)
      if (data.code === 200) {
        this.$message.success('编辑成功')
        this.editDialog.show = false
        this.initNodesData()
      } else {
        this.$message.error(data.msg)
      }
    },

    async add () {
      const params = {
        appid: this.queryParams.appid,
        button_id: parseInt(this.editDialog.button_id),
        button_name: this.editDialog.button_name,
        parent_id: this.editDialog.parent_id
      }
      const data = await addButtonEventApi(params)

      if (data.code === 200) {
        this.$message.success('添加成功')
        this.editDialog.show = false
        this.initNodesData()
      } else {
        this.$message.error(data.msg)
      }
    },
    handleHeaderAction (action, params) {
      const methods = {
        select: this.selectAll,
        revert: this.revertAll,
        del: this.del,
        add: this.setEditDialog.bind(this, { type: 'add', title: '添加事件', parent_id: null }),
        change: this.importfile,
        preview: this.preview,
        confirm: this.confirm,
        import: this.importfile
      }
      methods[action] && methods[action](params)
    },

    async del () {
      const ids = this.list.filter(item => item.checked === 'checked').map(item => item.button_id)
      const params = {
        appid: this.queryParams.appid,
        button_ids: ids.join(',')
      }
      if (ids.length === 0) {
        this.$message.error('请选择要删除的事件ID')
        return
      }

      this.$confirm('确定删除所选事件吗？', '删除事件').then(async () => {
        const data = await deleteButtonEventApi(params)
        if (data.code === 200) {
          this.$message.success('删除成功')
          this.initNodesData()
        } else {
          this.$message.error(data.msg)
        }
      })
    },
    // 导入文件
    async importfile (file) {
      const reader = new FileReader()
      reader.onload = (e) => {
        const data = new Uint8Array(e.target.result)
        const workbook = read(data, { type: 'array' })
        const sheetname = workbook.SheetNames[0]
        const worksheet = workbook.Sheets[workbook.SheetNames[0]]
        const csvString = utils.sheet_to_csv(worksheet, { blankrows: false })
        // console.log(csvString)
        const csvfile = new File([csvString], `${sheetname}.csv`, { type: 'text/csv' })
        this.uploadCsv(csvfile)
      }
      reader.readAsArrayBuffer(file)
    },
    // 上传文件
    async uploadCsv (file) {
      const formdata = new FormData()
      formdata.append('appid', this.queryParams.appid)
      formdata.append('file', file)
      const data = await uploadBatchButtonEventApi(formdata)
      if (data.code === 200) {
        this.$message.success('上传成功')
        this.preview()
      } else {
        this.$message.error('上传失败')
      }
    },
    formatListData (list) {
      const values = []
      function recursion (arr, parent) {
        for (let i = 0; i < arr.length; i++) {
          const item = arr[i]
          const btn = { ...item.ButtonInfo, status: item.ButtonStatus }
          parent.push(btn)
        }
      }
      recursion(list, values)
      return values
    },
    async preview () {
      const data = await previewBatchButtonEventApi({ appid: this.queryParams.appid })
      if (data.code === 200) {
        if (data.data === null) {
          this.$message.info('没有需要预览的数据')
          return
        }
        this.previewNodes = this.formatListData(data.data || [])
        return
      }
      this.$message.error(data.msg)
    },
    async confirm () {
      const hasInvalited = this.previewNodes.some(item => item.status === 3)
      if (hasInvalited) {
        this.$message.error('存在无效数据，请修改后重试')
        return
      }
      const data = await confirmBatchButtonEventApi({ appid: this.queryParams.appid })
      if (data.code === 200) {
        this.$message.success('导入成功')
        this.initNodesData()
        return
      }
      this.$message.error(data.msg)
    },
    formatListDataInit (list) {
      const values = []
      const allNodes = new Map()
      let maxId = 0
      let index = 0
      function recursion (arr, parent_ids, layer = 0) {
        for (let i = 0; i < arr.length; i++) {
          const item = arr[i]
          const btn = {
            ...item.ButtonInfo,
            id: item.ButtonInfo.button_id,
            parent_id: parent_ids[parent_ids.length - 1] || '',
            parent_ids,
            layer,
            childs: item.Children?.map((v) => v.ButtonInfo.button_id) || [],
            index,
            checked: '' // checked, half-checked, '' // 选中，半选中，未选中
          }
          values.push(btn)
          allNodes.set(item.ButtonInfo.button_id, btn)
          maxId = Math.max(maxId, item.ButtonInfo.button_id)
          index++
          if (item.Children) {
            const ids = parent_ids.concat()
            ids.push(item.ButtonInfo.button_id)
            recursion(item.Children, ids, layer + 1)
          }
        }
      }
      recursion(list, [], 0)
      console.log(allNodes, '-------')
      return { values, allNodes, maxId }
    },
    async initNodesData () {
      const params = { ...this.queryParams, mode: 1, button_id: '', date: parseTime(Date.now() - 3600 * 24 * 1000, '{y}-{m}-{d}') }
      const data = await getButtnEventListApi(params)
      const { allNodes, values, maxId } = this.formatListDataInit(data.data || [])
      this.nodes = allNodes
      this.maxId = maxId
      this.list = values
    }
  },
  mounted () {
    this.initNodesData()
  }
}
</script>

<style lang="scss" scoped>
.page__report_manage {
  // display: flex;
  width: 100%;
  height: 100%;
  overflow: hidden;
}
.comp__report_manager{
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}
.list__body {
  margin-top: 20px;
  flex: 1 1 100%;
  overflow: hidden;
}
</style>
